package com.sinosoft.user.controller;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.io.IOException;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSONObject;
import com.sinosoft.common.core.domain.R;
import com.sinosoft.common.core.utils.sign.Base64;
import com.sinosoft.user.api.RemoteFlowService;
import com.sinosoft.user.utils.CommUtil;
import feign.Feign;
import feign.Response;
import io.swagger.annotations.ApiOperation;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.common.engine.impl.javax.el.ELException;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.sinosoft.common.log.annotation.Log;
import com.sinosoft.common.log.enums.BusinessType;
import com.sinosoft.common.security.annotation.PreAuthorize;
import com.sinosoft.user.domain.TestFlow;
import com.sinosoft.user.service.ITestFlowService;
import com.sinosoft.common.core.web.controller.BaseController;
import com.sinosoft.common.core.web.domain.AjaxResult;
import com.sinosoft.common.core.utils.poi.ExcelUtil;
import com.sinosoft.common.core.web.page.TableDataInfo;

/**
 * 流程验证Controller
 *
 * @author sinosoft
 * @date 2022-02-22
 */
@RestController
@RequestMapping("/testflow")
public class TestFlowController extends BaseController
{
    @Autowired
    private ITestFlowService testFlowService;

    @Autowired
    private RemoteFlowService remoteFlowService;


    @Resource
    private RuntimeService runtimeService;

    @Resource
    HistoryService historyService;

    @Resource
    RepositoryService repositoryService;

    @Resource
    private TaskService taskService;

    @Resource
    private IdentityService identityService;

    /**
     * 查询流程验证列表
     */
    @PreAuthorize(hasPermi = "flow:testflow:list")
    @GetMapping("/list")
    public TableDataInfo list(TestFlow testFlow)
    {
        startPage();
        List<TestFlow> list = testFlowService.selectTestFlowList(testFlow);
        return getDataTable(list);
    }

    /**
     * 导出流程验证列表
     */
    @PreAuthorize(hasPermi = "flow:testflow:export")
    @Log(title = "流程验证", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, TestFlow testFlow) throws IOException
    {
        List<TestFlow> list = testFlowService.selectTestFlowList(testFlow);
        ExcelUtil<TestFlow> util = new ExcelUtil<TestFlow>(TestFlow.class);
        util.exportExcel(response, list, "流程验证数据");
    }

    /**
     * 获取流程验证详细信息
     */
    @PreAuthorize(hasPermi = "flow:testflow:query")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id)
    {
        return AjaxResult.success(testFlowService.selectTestFlowById(id));
    }

    /**
     * 新增流程验证
     */
    @PreAuthorize(hasPermi = "flow:testflow:add")
    @Log(title = "流程验证", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody TestFlow testFlow)
    {
        return toAjax(testFlowService.insertTestFlow(testFlow));
    }

    /**
     * 修改流程验证
     */
    @PreAuthorize(hasPermi = "flow:testflow:edit")
    @Log(title = "流程验证", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody TestFlow testFlow)
    {
        return toAjax(testFlowService.updateTestFlow(testFlow));
    }

    /**
     * 删除流程验证
     */
    @PreAuthorize(hasPermi = "flow:testflow:remove")
    @Log(title = "流程验证", businessType = BusinessType.DELETE)
	@DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids)
    {
        return toAjax(testFlowService.deleteTestFlowByIds(ids));
    }

    /**
     * 启动流程
     */
    @PreAuthorize(hasPermi = "flow:testflow:start")
    @Log(title = "流程启动", businessType = BusinessType.UPDATE)
    @PostMapping("/startflow")
    public AjaxResult startFlow(@RequestParam Long id,@RequestParam String flowId,@RequestBody JSONObject vars)
    {
        // 设置发起人
        identityService.setAuthenticatedUserId("admin");

        //设置条件参数
        Map<String, Object> varMap = new HashMap<>(8);
        //写入数据权限部门(其他条件参数也一样, 只要流程执行中涉及到的自定义参数, 都需要写入该Map之中)
        varMap.put("departmentId", "dept_test");

        ProcessInstance processInstance;
        try {
            //deploy.getDeployModelId() 为之前流程部署时返回的流程模板ID, varMap为上文创建的流程变量集合对象
            //processInstance = runtimeService.startProcessInstanceById(modelId, businessKey, varMap);
            processInstance = runtimeService.startProcessInstanceByKey(flowId,String.valueOf(id),varMap);
            //返回启动后的流程实例ID
            return AjaxResult.success(processInstance.getProcessInstanceId());
        } catch (Exception e) {
            //捕捉EL表达式中抛出的异常
            if (e.getCause() instanceof ELException && e.getCause().getCause() instanceof RuntimeException) {
                throw new RuntimeException(e.getCause().getCause().getMessage());
            }
//            log.info("[FlowApiServiceImpl].[startFlow] ------> Business System Startup Process, Start, params = {}", JSON.toJSONString(params));
//            log.error("[FlowApiServiceImpl].[startFlow] ------> Business System Startup Process, Error, e:", e);
            throw new RuntimeException("启动流程异常:" + e.getMessage());
        }
    }


    @GetMapping("/getTasks")
    @ApiOperation("测试获取待办任务列表")
    public List<Map<String, Object>> getTasks(@RequestParam String userKey){
        try {
            List<Map<String, Object>> listMap = new ArrayList<>();
            List<Task> tasks = taskService.createTaskQuery().taskAssignee(userKey).list();
            //返回启动后的流程实例ID
            String[] ps = { "owner", "processInstanceId", "processDefinitionId", "suspensionState", "formKey", "priority", "executionId",
                    "taskDefinitionKey" , "subTaskCount" , "createTime" , "name" , "isCountEnabled" , "variableCount" , "assignee" ,
                    "identityLinkCount" , "category"};
            for (Task pd : tasks) {
                Map<String, Object> map = CommUtil.obj2map(pd, ps);
                listMap.add(map);
            }
            return listMap;
        } catch (Exception e) {
            throw new RuntimeException("获取任务列表异常:" + e.getMessage());
        }
    }

    @PreAuthorize(hasPermi = "flow:testflow:flowDiagram")
    @RequestMapping("/flowDiagram")
    public void flowDiagram(@RequestParam String businessKey, HttpServletResponse response) throws Exception
    {
        ProcessInstance pi = runtimeService
                .createProcessInstanceQuery()
                .processInstanceBusinessKey(businessKey)
                .singleResult();
        if (pi == null) {
            return;
        }

        String processId = pi.getProcessInstanceId();
        List<HistoricActivityInstance> historyProcess = getHistoryProcess(processId);
        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        for (HistoricActivityInstance hi : historyProcess) {
            String activityType = hi.getActivityType();
            if (activityType.equals("sequenceFlow") || activityType.equals("exclusiveGateway")) {
                flows.add(hi.getActivityId());
            } else if (activityType.equals("userTask") || activityType.equals("startEvent")) {
                activityIds.add(hi.getActivityId());
            }
        }
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(processId).list();
        for (Task task : tasks) {
            activityIds.add(task.getTaskDefinitionKey());
        }
        ProcessEngineConfiguration engConf = processEngine().getProcessEngineConfiguration();
        //定义流程画布生成器
        ProcessDiagramGenerator processDiagramGenerator = engConf.getProcessDiagramGenerator();
        InputStream in = processDiagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows,"宋体","宋体","宋体",null,1.0, false);
      //  InputStream in = processDiagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engConf.getActivityFontName(), engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, true);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = response.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }

    @PreAuthorize(hasPermi = "flow:testflow:completeTask")
    @PutMapping("/completeTask")
    public String completeTask(@RequestParam String businessKey)
    {
        try {
            ProcessInstance pi = runtimeService
                    .createProcessInstanceQuery()
                    .processInstanceBusinessKey(businessKey)
                    .singleResult();
            List<Task> tasks =  taskService.createTaskQuery().processInstanceBusinessKey(businessKey).list();
          //  ExecutionEntity ee =(ExecutionEntity) processEngine().getRuntimeService().createExecutionQuery()
          //          .processInstanceBusinessKey(businessKey).singleResult();
           // runtimeService.createProcessInstanceQuery().processInstanceId(pi.getProcessDefinitionId()).singleResult();
            // 当前审批节点
          //  String crruentActivityId = ee.getActivityId();
          //  List<TaskEntity> tasks = ee.getTasks();
            if(tasks.size()==1){
                Task task = tasks.iterator().next();
                taskService.complete(task.getId());
            }
           // taskService.complete(taskId);
            return "办理成功！";
        } catch (Exception e) {
            throw new RuntimeException("任务办理异常:" + e.getMessage());
        }
    }

    /**
     * 任务历史
     *
     * @param processId 部署id
     */
    public List<HistoricActivityInstance> getHistoryProcess(String processId) {
        List<HistoricActivityInstance> list = historyService // 历史相关Service
                .createHistoricActivityInstanceQuery() // 创建历史活动实例查询
                .processInstanceId(processId) // 执行流程实例id
                .finished()
                .list();
        return list;
    }

    public ProcessEngine processEngine() {
        return ProcessEngines.getDefaultProcessEngine();
    }
}
